/**
 * redux中的最核心api：createStore，它是用来创建store对象的
 * 调用createStore方法时要传递的3个参数：createStore(reducer, preloadedState, enhancer)
 *  1.reducer函数：根据action的类型对store当中的状态进行更改
 *  2.preloadedState：预存储的store状态
 *  3.enhancer：对store的功能进行增强
 * createStore方法返回一个对象：
 *  {
 *    getState,
 *    dispatch,
 *    subscribe
 *  }
 */

function createStore(reducer, preloadedState, enhancer) {
  // 约束reducer参数类型
  if (typeof reducer !== "function") throw new Error("reducer必须是一个函数");
  // 判断enhancer是否传递
  if (typeof enhancer !== "undefined") {
    // 判断enhancer是不是一个函数
    if (typeof enhancer !== "function")
      throw new Error("enhancer必须是一个函数");
    return enhancer(createStore)(reducer, preloadedState);
  }
  // store对象中存储的状态
  var currentState = preloadedState;
  // 存放订阅者函数
  var currentListeners = [];
  // 获取状态
  function getState() {
    return currentState;
  }
  // 触发action
  function dispatch(action) {
    // 判断action是否是一个对象
    if (!isPlainObject(action)) throw new Error("action必须是一个对象");
    // 判断对象中是否具有type属性
    if (typeof action.type === "undefined")
      throw new Error("action对象中必须要有type属性");
    currentState = reducer(currentState, action);
    // 循环数组 调用订阅者
    for (var i = 0; i < currentListeners.length; i++) {
      // 获取订阅者
      var listener = currentListeners[i];
      // 调用订阅者
      listener();
    }
  }
  // 订阅状态
  function subscribe(listener) {
    currentListeners.push(listener);
  }

  return {
    getState,
    dispatch,
    subscribe,
  };
}

// 判断obj参数是否是对象
function isPlainObject(obj) {
  // 排除基本数据类型和null
  if (typeof obj !== "object" || obj === null) return false;
  // 区分数组和对象 原型对象对比的方式
  var proto = obj;
  while (Object.getPrototypeOf(proto) !== null) {
    proto = Object.getPrototypeOf(proto);
  }
  return Object.getPrototypeOf(obj) === proto;
}

function applyMiddleware(...middlewares) {
  return function (createStore) {
    return function (reducer, preloadedState) {
      // 创建store
      var store = createStore(reducer, preloadedState);
      // 阉割版的store
      var middlewareAPI = {
        getState: store.getState,
        dispatch: store.dispatch,
      };
      // 调用中间件的第一层函数 传递阉割版的store
      var chain = middlewares.map((middleware) => middleware(middlewareAPI));
      var dispatch = compose(...chain)(store.dispatch);
      return {
        ...store,
        dispatch,
      };
    };
  };
}

// 处理中间件的第二层函数
function compose() {
  var funcs = [...arguments]; // arguments转换成真正的数组
  // console.log(funcs);
  // 倒着循环才能先拿到thunk再到logger
  return function (dispatch) {
    for (var i = funcs.length - 1; i >= 0; i--) {
      dispatch = funcs[i](dispatch); // 最后一个循环完是logger的最里层函数
    }
    return dispatch;
  };
}

function bindActionCreators(actionCreators, dispatch) {
  var boundActionCreators = {};
  for (var key in actionCreators) {
    (function (key) {
      boundActionCreators[key] = function () {
        dispatch(actionCreators[key]());
      };
    })(key);
  }
  return boundActionCreators;
}

function combineReducers(reducers) {
  // 1.检查reducer类型，它必须是函数
  var reducerKeys = Object.keys(reducers);
  for (var i = 0; i < reducerKeys.length; i++) {
    var key = reducerKeys[i];
    if (typeof reducers[key] !== "function")
      throw new Error("reducer必须是函数");
  }
  // 2.调用一个一个的小的reducer 将每一个小的reducer中返回的状态存储在一个新的大的对象中
  return function (state, action) {
    var nextState = {};
    for (var i = 0; i < reducerKeys.length; i++) {
      var key = reducerKeys[i];
      var reducer = reducers[key];
      var previousStateForKey = state[key];
      nextState[key] = reducer(previousStateForKey, action);
    }
    return nextState;
  };
}
